package nr.nodehost;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.Random;
import java.util.Vector;

import net.sf.json.JSONObject;

public class Utils {
    public static int bytes2int(byte[] bytes, int offset) {
        if (bytes.length - offset < 4)
            return 0;
        return ((0xFF & bytes[offset + 3]) << 24) + ((0xFF & bytes[offset + 2]) << 16) + ((0xFF & bytes[offset + 1]) << 8) + (0xFF & bytes[offset]);
    }

    public static int bytes2long(byte[] bytes, int offset) {
        if (bytes.length - offset < 4)
            return 0;
        int result = 0;
        for (int i = 3; i >= 0; i--) {
            long temp = (0xFF & bytes[offset + i]);
            temp <<= (i * 8);
            result += temp;
        }

        return result;
    }

    public static byte[] int2bytes(int value) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (value & 0xFF);
        bytes[1] = (byte) ((value >> 8) & 0xFF);
        bytes[2] = (byte) ((value >> 16) & 0xFF);
        bytes[3] = (byte) ((value >> 24) & 0xFF);
        return bytes;
    }

    public static void int2bytes(int value,byte[] bytes,int offset) {
        bytes[offset++]=(byte)(value>>24);
        bytes[offset++]=(byte)(value>>16);
        bytes[offset++]=(byte)(value>>8);
        bytes[offset++]=(byte)(value&0xFF);
    }

    public static String getShellCommandOutput(String command) {
        String output = null;
        try {
            ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
            pb.redirectErrorStream(true);
            Process process = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder builder = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
                builder.append(System.getProperty("line.separator"));
            }

            output = builder.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return output;
    }

    public static JSONObject getComponentResourceUsage(String schemaRunDir, int schemaId, String componentId) {
        JSONObject usage = new JSONObject();
        usage.put("%cpu", 0);
        usage.put("%mem", 0);
        usage.put("mem", 0);
        usage.put("disk", 0);
        usage.put("gpu", 0);
        try {
            String command = "ps aux|grep " + componentId + "|grep -v grep";
            String output = getShellCommandOutput(command);
            if (output != null) {
                String[] usageText = output.split(System.getProperty("line.separator"));

                if (usageText.length > 0) {
                    String[] usageItems = usageText[0].split("\\s+");
                    if (usageItems.length > 2)
                        usage.put("%cpu", Double.parseDouble(usageItems[2]));
                    if (usageItems.length > 3)
                        usage.put("%mem", Double.parseDouble(usageItems[3]));
                    if (usageItems.length > 5)
                        usage.put("mem", Double.parseDouble(usageItems[5]));

                }
            }
            //get cpu cores
            command = "cat /proc/cpuinfo |grep 'processor' |wc -l";
            output = getShellCommandOutput(command);
            if (output != null) {
                try {
                    String[] usageText = output.split(System.getProperty("line.separator"));
                    if (usageText.length > 0) {
                        int cores = Integer.parseInt(usageText[0]);
                        usage.put("cpu_cores", cores);
                        usage.put("%cpu", usage.getDouble("%cpu") / cores);
                    }
                } catch (Exception e) {

                }
            }
            //get total disk size
            command = "df /";
            output = getShellCommandOutput(command);
            if (output != null) {
                String[] usageText = output.split(System.getProperty("line.separator"));
                if (usageText.length > 1) {
                    String[] usageItems = usageText[1].split("\\s+");

                    if (usageItems.length > 1) {
                        usage.put("disk_total", Double.parseDouble(usageItems[1]));
                    }
                }
            }
            //get disk usage
            command = "du -s " + schemaRunDir + "/" + schemaId + "/" + componentId;
            output = getShellCommandOutput(command);
            if (output != null) {
                String[] usageItems = output.split("\\s+");
                if (usageItems.length > 0) {
                    usage.put("disk", Double.parseDouble(usageItems[0]));
                    usage.put("%disk", usage.getDouble("disk") * 100.0 / usage.getDouble("disk_total"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return usage;
    }

    public static JSONObject getSchemaResourceUsage(String schemaRunDir, int schemaId) {
        JSONObject usage = new JSONObject();
        usage.put("%cpu", 0);
        usage.put("%mem", 0);
        usage.put("mem", 0);
        usage.put("disk", 0);
        usage.put("%disk", 0);
        usage.put("gpu", 0);
        try {
            File schemaDir = new File(schemaRunDir + "/" + schemaId);
            String[] components = schemaDir.list();
            if (components != null) {
                for (int i = 0; i < components.length; i++) {
                    JSONObject componentUsage = getComponentResourceUsage(schemaRunDir, schemaId, components[i]);
                    usage.put("%cpu", usage.getDouble("%cpu") + componentUsage.getDouble("%cpu"));
                    usage.put("%mem", usage.getDouble("%mem") + componentUsage.getDouble("%mem"));
                    usage.put("mem", usage.getDouble("mem") + componentUsage.getDouble("mem"));
                    usage.put("%disk", usage.getDouble("%disk") + componentUsage.getDouble("%disk"));
                    usage.put("disk", usage.getDouble("disk") + componentUsage.getDouble("disk"));
                    usage.put("gpu", usage.getDouble("gpu") + componentUsage.getDouble("gpu"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return usage;
    }

    public static JSONObject getSystemResourceUsage() {
        JSONObject usage = new JSONObject();
        usage.put("cpu", 0);
        usage.put("%cpu", 0);
        usage.put("mem", 0);
        usage.put("%mem", 0);
        usage.put("disk", 0);
        usage.put("%disk", 0);
        usage.put("gpu", 0);
        try {
			/*
			String command="ps aux|grep "+componentId+"|grep -v grep";
			String output=getShellCommandOutput(command);
			
			if(output!=null) {
				String[] usageText=output.split(System.getProperty("line.separator"));
				
				if(usageText.length>0) {
					String[] usageItems=usageText[0].split("\\s+");
					if(usageItems.length>2)
						usage.put("%cpu", Double.parseDouble(usageItems[2]));
					if(usageItems.length>3)
						usage.put("%mem", Double.parseDouble(usageItems[3]));
					if(usageItems.length>5)
						usage.put("mem", Double.parseDouble(usageItems[5]));
					
				}
			}
			*/
            String command = "free -m";
            String output = getShellCommandOutput(command);
            if (output != null) {
                String[] usageText = output.split(System.getProperty("line.separator"));
                if (usageText.length > 1) {
                    String[] usageItems = usageText[1].split("\\s+");

                    if (usageItems.length > 1) {
                        usage.put("mem", Double.parseDouble(usageItems[1]));
                    }
                    if (usageItems.length > 2) {
                        usage.put("%mem", Double.parseDouble(usageItems[2]) * 100.0 / usage.getDouble("mem"));
                    }
                }
            }
            //get cpu cores
            command = "cat /proc/cpuinfo |grep 'processor' |wc -l";
            output = getShellCommandOutput(command);
            if (output != null) {
                try {
                    String[] usageText = output.split(System.getProperty("line.separator"));
                    if (usageText.length > 0) {
                        int cores = Integer.parseInt(usageText[0]);
                        usage.put("cpu", cores);
                        //usage.put("%cpu", usage.getDouble("%cpu")/cores);
                    }
                } catch (Exception e) {

                }
            }
            //get total disk size
            command = "df /";
            output = getShellCommandOutput(command);
            if (output != null) {
                String[] usageText = output.split(System.getProperty("line.separator"));
                if (usageText.length > 1) {
                    String[] usageItems = usageText[1].split("\\s+");

                    if (usageItems.length > 1) {
                        usage.put("disk", Double.parseDouble(usageItems[1]));
                    }
                    if (usageItems.length > 2) {
                        usage.put("%disk", Double.parseDouble(usageItems[2]) * 100.0 / usage.getDouble("disk"));
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return usage;
    }

    public static boolean runProgram(String path, String program, File programOutputFile) {
        boolean result = true;
        System.out.println("run program " + program);
        //String program=executor.getProgram();
        try {
            Vector<String> command = new Vector<String>();//cmdlineToCommand(compileCmdLine,compileDir);

            command.add(path + "/" + program);
            //command.add(""+executor.getNextFrameNo());

            //File programOutputFile=new File(executor.getProgramDir()+"/"+executor.getComponentId()+".err");
            ProcessBuilder pb = new ProcessBuilder(command);
            //Map<String, String> env = pb.environment();
            //set environment variable u
            //System.out.println("set LD_LIBRARY_PATH to "+executor.getComponentRunLibPath());
            //env.put("LD_LIBRARY_PATH", executor.getComponentRunLibPath());
            pb.redirectOutput(programOutputFile);
            long startTime = System.currentTimeMillis();
            pb.directory(new File(path));
            pb.redirectErrorStream(true);
            Process p = pb.start();
			/*
			boolean terminated=false;
			int exitValue=0;
			int waitTime=0;
			while(!terminated){//&&waitTime<MAX_COMPILE_TIME*1000
				try{
					exitValue=p.exitValue();
					
					terminated=true;
				}
				catch(IllegalThreadStateException e){
					waitTime+=100;
					Thread.sleep(100);
				}
				
			}
			if(terminated)
				System.out.println("component process teminated, exitValue="+exitValue);
			else{
				System.out.println("component process timeout,need destroy.");
				p.destroy();
			}
			*/
        } catch (Exception e) {
            e.printStackTrace();
            result = false;
        }
        return result;
    }

    public static ArrayList<String> getLocalIpAddress() {
        ArrayList<String> ipList = new ArrayList<String>();
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) interfaces.nextElement();
                Enumeration<InetAddress> ipAddrEnum = ni.getInetAddresses();
                while (ipAddrEnum.hasMoreElements()) {
                    InetAddress addr = (InetAddress) ipAddrEnum.nextElement();
                    if (addr.isLoopbackAddress() == true) {
                        continue;
                    }

                    String ip = addr.getHostAddress();
                    if (ip.indexOf(":") != -1) {
                        //skip the IPv6 addr
                        continue;
                    }

                    System.out.println("Interface: " + ni.getName() + ", IP: " + ip);
                    ipList.add(ip);
                }
            }

            Collections.sort(ipList);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return ipList;
    }

    public static void main(String[] args) {
        byte[] data = {-28, -92, -109, -42};
        long n = Utils.bytes2long(data, 0);
        System.out.println(n);
        getLocalIpAddress();
        try {
            ProcessBuilder pb = new ProcessBuilder();
            Map<String, String> env = pb.environment();
            //set environment variable u
            //env.put("LD_LIBRARY_PATH", "./:/usr/local/MATLAB/R2020a/runtime/glnxa64");

            pb.command("/home/wanbo/nr/libtest/demo");
            //pb.redirectOutput(new File("/home/wanbo/nr/libtest/run.out"));
            //long startTime=System.currentTimeMillis();
            pb.directory(new File("/home/wanbo/nr/libtest/"));
            pb.redirectErrorStream(true);
            //pb.redirectOutput(new File("/home/wanbo/nr/libtest/out.txt"));
            Process p = pb.start();
            BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
            //BufferedOutputStream out=new BufferedOutputStream(p.getOutputStream());
            PrintStream out = new PrintStream(p.getOutputStream());
            //Random rand=new Random();

            for (int frameno = 10; frameno >= 0; frameno--) {

                //int ret=Integer.parseInt(input.readLine());
                //Thread outputThread = new ProcessOutputThread(p.getInputStream());
                //outputThread.start();
                //int frameno=rand.nextInt()%10;
                //BufferedOutputStream out=new BufferedOutputStream(p.getOutputStream());
                //out.write(new String(Integer.toString(frameno)+"\n").getBytes());
                out.println(frameno);
                out.flush();
                //out.close();
                //out.println(frameno);
                //out.println();
                //out.close();
                //outputThread.join();
                //System.out.println(ret);
	        	/*
	        	if(ret==0) {
	        		
	        		while(!terminated){//&&waitTime<MAX_COMPILE_TIME*1000
						try{
							int exitValue=p.exitValue();
							System.out.println("exitValue:"+exitValue);
							terminated=true;
						}
						catch(IllegalThreadStateException e){
							//waitTime+=100;
							Thread.sleep(100);
						}
						
					}
	        	}
	        	*/
                String line = input.readLine();
                System.out.println(line);
	        	/*
	        	while((line=input.readLine())!=null) {
	        		System.out.println(line);
	        	}
	        	*/

            }
            out.close();
            input.close();
            boolean terminated = false;
            while (!terminated) {//&&waitTime<MAX_COMPILE_TIME*1000
                try {
                    int exitValue = p.exitValue();
                    System.out.println("exitValue:" + exitValue);
                    terminated = true;
                } catch (IllegalThreadStateException e) {
                    //waitTime+=100;
                    Thread.sleep(100);
                }

            }

            System.out.println("terminated.");
            //String output = loadStream(p.getInputStream());
            //String error  = loadStream(p.getErrorStream());
            //int rc = p.waitFor();
            //System.out.println("Process ended with rc=" + rc);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //System.out.println("\nStandard Output:\n");
        //System.out.println(output);
        //System.out.println("\nStandard Error:\n");
        //System.out.println(error);
    }
}
